home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / wais / ir / ircfiles.c < prev    next >
Text File  |  1995-05-09  |  44KB  |  1,928 lines

  1.  /* WIDE AREA INFORMATION SERVER SOFTWARE:
  2.    No guarantees or restrictions.  See the readme file for the full standard
  3.    disclaimer.
  4.  
  5.    Brewster@think.com
  6. */
  7.  
  8. /* this file defines a set of helper functions
  9.  * for indexing common types of files.
  10.  * -brewster 7/90
  11.  */
  12.  
  13. /* I encourage adding customizations.
  14.  * (too bad they all have to be hard coded, but
  15.  *  C did not have convenient dynamic linking facilities)
  16.  *
  17.  * Add three functions to this file:
  18.  * boolean foo_separator_function(char *line){}
  19.  * void foo_header_function(char *line){}
  20.  * long foo_date_function(char *line){}
  21.  * void foo_finish_header_function(char *header){}
  22.  *
  23.  * then add the prototypes to ircfiles.h
  24.  * then add the functions to the big case statement in irbuild.c
  25.  *
  26.  *
  27.  * to do:
  28.  *   filter for digests
  29.  *
  30.  *   Tracy pointed out 2 things which we should consider when redesigning the
  31.  *   parser:
  32.  *
  33.  *   - there should be a way for the parser to decide to skip a section of 
  34.  *   input text (ie. not index it).  she does this by having global variable 
  35.  *   which is set by her custom seperator function when it wants to tell 
  36.  *   map_over_words() to not add the words on the current line
  37.  *
  38.  *   - there should be a way to switch lexers depending what section of a
  39.  *   document you are in (since word separators will change).  This is 
  40.  *   needed by the european patent office too.
  41.  *
  42.  */
  43.  
  44.  
  45. /* Change log:
  46.  * 8/90 brewster added the library customizations
  47.  * 6/91 and before - added a bunch of other filters - JG
  48.  * $Log:    ircfiles.c,v $
  49.  * Revision 1.34  92/05/06  17:28:23  jonathan
  50.  * Added filename_finish_header_function.  Puts leaf name into header.
  51.  * 
  52.  * Revision 1.33  92/05/05  11:10:50  jonathan
  53.  * Added fix to bibtex indexer to ignore subsequent "booktitles" after title
  54.  * has been set.  Thanks to Lutz Prechelt (prechelt@ira.uka.de).
  55.  * 
  56.  * Revision 1.32  92/04/30  12:31:08  jonathan
  57.  * Fixed syntax errors in OBJ C functions.
  58.  * 
  59.  * Revision 1.31  92/04/29  14:08:57  shen
  60.  * chnage catalaog header string to "Title:"
  61.  * 
  62.  * Revision 1.30  92/04/26  14:45:08  brewster
  63.  * debug ziff
  64.  * 
  65.  * Revision 1.29  92/04/26  14:39:24  brewster
  66.  * tweeked ziff filter
  67.  * 
  68.  * Revision 1.28  92/04/25  21:14:05  brewster
  69.  * added ziff
  70.  * 
  71.  * Revision 1.27  92/04/20  15:21:06  morris
  72.  * added todo's for tracy
  73.  * 
  74.  * Revision 1.26  92/03/22  18:38:29  brewster
  75.  * added objective C filter
  76.  * 
  77.  * Revision 1.25  92/03/13  08:21:37  jonathan
  78.  * Added length limits to scanf's in my_getdate, thanks to
  79.  * sendall@dxpt01.cern.ch (Mike Sendall).
  80.  * 
  81.  * Revision 1.24  92/02/29  20:13:54  jonathan
  82.  * separated =- for some compilers that get confused (ULTRIX).
  83.  * 
  84.  * Revision 1.23  92/02/20  09:50:14  jonathan
  85.  * Added bibtex and nhyp filters from S.P.vandeBurgt@research.ptt.nl.
  86.  * 
  87.  * Revision 1.22  92/02/12  13:11:25  jonathan
  88.  * Changed library catalog functions for new format (from fad).
  89.  * 
  90.  * 
  91.  *
  92.  */
  93.  
  94. #include <string.h>
  95. #include <ctype.h>
  96. #include "cutil.h"
  97. #include "ircfiles.h"
  98.  
  99. extern char *current_filename;
  100. extern int current_filecount;
  101.  
  102. #define MAX_HEADER_LEN 100
  103.  
  104. #define MAX_AUTHOR_LEN 25
  105. #define MAX_DATE_LEN 4
  106.  
  107. static char* trim_trailing_newline _AP((char* string));
  108.  
  109. static char*
  110. trim_trailing_newline(string)
  111. char* string;
  112. {
  113.   if(string)
  114.     if(strlen(string) > 0)
  115.       if(string[strlen(string) -1] == '\n')
  116.     string[strlen(string) -1] = '\0';
  117.   return(string);
  118. }
  119.  
  120. /* =================================
  121.  * ===  Groliers Customizations  ===
  122.  * =================================
  123.  */
  124.  
  125. boolean groliers_separator_function(line)
  126. char *line;
  127. {
  128.   if((strlen(line) > strlen("ARTICLE")) &&
  129.      substrcmp(line, "ARTICLE")){
  130.     /* printf("hit %s\n", line); */
  131.     return(true);
  132.   }
  133.   else{
  134.     return(false);
  135.   }
  136. }
  137.  
  138. char groliers_header[MAX_HEADER_LEN + 1];
  139.  
  140. void groliers_header_function(line)
  141. char *line;
  142. {
  143.   if(groliers_separator_function(line)){
  144.     s_strncpy(groliers_header, line + strlen("ARTICLE") + 2, MAX_HEADER_LEN);
  145.   }
  146. }
  147.  
  148. void groliers_finish_header_function(header)
  149. char *header;
  150. {
  151.   if(strlen(groliers_header) == 0){
  152.     s_strncpy(header, "Unknown Title", MAX_HEADER_LEN);
  153.   }
  154.   else{
  155.     s_strncpy(header, groliers_header, MAX_HEADER_LEN);
  156.   }
  157.   groliers_header[0] = '\0';
  158. }
  159.  
  160.  
  161. /* ==============================
  162.  * ===  RMail Customizations  ===
  163.  * ==============================
  164.  */
  165.  
  166. /* this is just a preliminary version. A good version would
  167.  * produce a headline like gnu emacs RMAIL
  168.  */
  169.  
  170.  
  171. boolean mail_separator_function(line)
  172. char *line;
  173. {
  174.   /* this should really look for a "<cr><cr>From " rather than "<cr>From " */
  175.   if((strlen(line) > strlen("From ")) &&
  176.      substrcmp(line, "From ")){
  177.     return(true);
  178.   }
  179.   else{
  180.     return(false);
  181.   }
  182. }
  183.  
  184. boolean rmail_separator_function(line)
  185. char *line;
  186. {
  187.   if(0 == strcmp(line, " \n")){
  188.     return(true);
  189.   }
  190.   else{
  191.     return(false);
  192.   }
  193. }
  194.  
  195. /* This one is portable, but might get the wrong answer.
  196.    I'm open to better code.  - Jonny G
  197. */
  198.  
  199. static char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
  200.             "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", NULL};
  201.  
  202. long my_getdate(line)
  203. char *line;
  204. {
  205.   char date[255], *temp;
  206.   int day, month, year;
  207.   char cmonth[25], dow[5], tod[10];
  208.  
  209.   strcpy(date, line);
  210.  
  211.   temp = date;
  212.  
  213.   while(!isdigit(*temp)) temp++;
  214.  
  215.   sscanf(temp, "%d %25s %d", &day, cmonth, &year);
  216.  
  217.   for(month = 0; months[month] != NULL; month++)
  218.     if(!strcmp(cmonth, months[month])) break;
  219.  
  220.   if (year > 99) year = year % 100;
  221.  
  222.   if(day > 0 && 
  223.      month < 12 &&
  224.      year > 0) {
  225.     return (10000 * year + 100 * (month+1) + day);
  226.   }
  227.  
  228.   month = -1; day = -1; year = -1;
  229.  
  230.   sscanf(temp, "%d/%d/%d", &month, &day, &year);
  231.  
  232.   if (year > 99) year = year % 100;
  233.  
  234.   if(day > 0 && 
  235.      month < 12 &&
  236.      year > 0) {
  237.     return (10000 * year + 100 * (month+1) + day);
  238.   }
  239.  
  240.   month = -1; day = -1; year = -1;
  241.  
  242.   sscanf(temp, "%d/%d/%d", &year, &month, &day);
  243.  
  244.   if (year > 99) year = year % 100;
  245.  
  246.   if(day > 0 && 
  247.      month < 12 &&
  248.      year > 0) {
  249.     return (10000 * year + 100 * (month+1) + day);
  250.   }
  251.  
  252.   temp = date;
  253.  
  254.   sscanf(temp, "%5s %25s %d %10s %d", dow, cmonth, &day, tod, &year);
  255.  
  256.   for(month = 0; months[month] != NULL; month++)
  257.     if(!strcmp(cmonth, months[month])) break;
  258.  
  259.   if (year > 99) year = year % 100;
  260.  
  261.   if(day > 0 && 
  262.      month < 12 &&
  263.      year > 0) {
  264.     return (10000 * year + 100 * (month+1) + day);
  265.   }
  266.  
  267.   return 0;
  268. }
  269.  
  270. long mail_date_function(line)
  271. char *line;
  272. {
  273.   if((strlen(line) > strlen("Date: ")) &&
  274.      substrcmp(line, "Date: ")){
  275.     return(my_getdate(line+6));
  276.   }
  277.   else if((strlen(line) > strlen("From ")) &&
  278.       substrcmp(line, "From ")){
  279.     char *p;
  280.     p = (char*)index(line+5, ' ');
  281.     if(p != NULL)
  282.       return(my_getdate(p+1));
  283.   }
  284.   else return -1;
  285. }
  286.  
  287.   
  288.  
  289. char mail_subject[MAX_HEADER_LEN + 1];
  290. char mail_from[MAX_HEADER_LEN + 1];
  291.  
  292. void mail_header_function(line)
  293. char *line;
  294. {
  295.   if((strlen(line) > strlen("Subject: ")) &&
  296.      substrcmp(line, "Subject: ") &&
  297.      (strlen(mail_subject) == 0)){
  298.     strcpy(mail_subject, "Re: ");
  299.     s_strncat(mail_subject, line + strlen("Subject: "), MAX_HEADER_LEN, MAX_HEADER_LEN);
  300.     trim_trailing_newline(mail_subject);
  301.   }
  302.   else if((strlen(line) > strlen("From: ")) &&
  303.      substrcmp(line, "From: ") &&
  304.      (strlen(mail_from) == 0)){
  305.     /* this should find the <foo@bar> field in the from list */
  306.     s_strncpy(mail_from, line + strlen("From: "), MAX_HEADER_LEN);
  307.     trim_trailing_newline(mail_from);
  308.   }
  309.   
  310. }
  311.  
  312. void mail_finish_header_function(header)
  313. char *header;
  314. {
  315.   if(strlen(mail_subject) != 0 &&
  316.      strlen(mail_from) != 0){
  317.     /* trim the from line if needed */
  318.     if(strlen(mail_from) > 10){
  319.       mail_from[10] = '\0';
  320.     }
  321.     s_strncpy(header, mail_from, MAX_HEADER_LEN);
  322.     s_strncat(header, " ", MAX_HEADER_LEN, MAX_HEADER_LEN);
  323.     s_strncat(header, mail_subject, MAX_HEADER_LEN, MAX_HEADER_LEN);
  324.   }
  325.   else if(strlen(mail_subject) != 0){
  326.     s_strncpy(header, mail_subject, MAX_HEADER_LEN);
  327.   }
  328.   else if(strlen(mail_from) != 0){
  329.     s_strncpy(header, mail_from, MAX_HEADER_LEN);
  330.   }
  331.   else{
  332.     strcpy(header, "Unknown Subject");
  333.   }
  334. /* printf("%s\n", header);  lots of output !! */
  335.  
  336.   mail_from[0] = '\0';
  337.   mail_subject[0] = '\0';
  338. }
  339.  
  340.  
  341.  
  342.  
  343. boolean mail_or_rmail_separator(line)
  344. char *line;
  345. {
  346.   static boolean blank_line = false;
  347.  
  348.   if((strlen(line) > strlen("From ")) &&
  349.      substrcmp(line, "From ") &&
  350.      blank_line == true){
  351.     blank_line = false;
  352.     return(true);
  353.   }
  354.   
  355.   if(substrcmp(line, "")){
  356.     blank_line = true;
  357.     return(true);
  358.   }    
  359.   
  360.   if(!strcmp(line, "\n")){
  361.       blank_line = true;
  362.     }
  363.     else{
  364.       blank_line = false;
  365.     }
  366.  
  367.   return(false);
  368. }
  369.  
  370.  
  371. /* ========================================
  372.  * ===  MMDF Mail folder Customizations     ====
  373.  * ========================================
  374. ^A^A^A^A
  375. body
  376. ^A^A^A^A
  377. ^A^A^A^A
  378. next body
  379. ^A^A^A^A
  380.  */
  381.  
  382. boolean mmdf_separator_function(line)
  383. char *line;
  384. {
  385.   static boolean saw_start = false;
  386.  
  387.   if ( substrcmp(line, "") ) { 
  388.     if( saw_start == true) 
  389.         saw_start = false;  /* the second one is the end marker */
  390.     else saw_start = true;  
  391.  
  392.     if (saw_start)  { 
  393.         /*printf(" mmdf_separator_function returns true\n");  */
  394.         return (true); 
  395.     }
  396.   } 
  397.   /* mix in osf mail archives which are seperated by "=" on a line 
  398.    * by itself
  399.    */
  400.   if ( substrcmp(line, "=") ) {
  401.     return (true);
  402.   }
  403.   return (false); 
  404.  
  405. #if 0
  406.  
  407.   if((strlen(line) > strlen("From ")) &&
  408.      substrcmp(line, "From ") &&
  409.      blank_line == true){
  410.     blank_line = false;
  411.     return(true);
  412.   }
  413.   
  414.   if(substrcmp(line, "")){
  415.     blank_line = true;
  416.     return(true);
  417.   }    
  418.   
  419.   if(!strcmp(line, "\n")){
  420.       blank_line = true;
  421.     }
  422.     else{
  423.       blank_line = false;
  424.     }
  425.  
  426.   return(false);
  427. #endif
  428. }
  429.  
  430.  
  431. /* ========================================
  432.  * ===  Mail Digest Customizations     ====
  433.  * ========================================
  434.  */
  435.  
  436. boolean mail_digest_separator_function(line)
  437. char *line;
  438. {
  439.   if((strlen(line) > strlen("-----------------------------")) &&
  440.      substrcmp(line, "------------------------------")){
  441.     return(true);
  442.   }
  443.   else{
  444.     return(false);
  445.   }
  446. }
  447.  
  448.  
  449. /* ========================================
  450.  * ===  Library Catalog Customizations  ===
  451.  * ========================================
  452.  */
  453.  
  454. #define TITLE_MARKER "Title: "
  455. #define FIRST_LINE_MARKER "Call No...."
  456.  
  457. /* just use the title */
  458.  
  459. boolean catalog_separator_function(line)
  460. char *line;
  461. {
  462.   if (strstr(line, FIRST_LINE_MARKER)) {
  463.     return(true);
  464.   }
  465.   else{
  466.     return(false);
  467.   }
  468. }
  469.  
  470. char catalog_header[MAX_HEADER_LEN + 1];
  471.  
  472. void catalog_header_function(line)
  473. char *line;
  474. {
  475.   char * title_start;
  476.   if (title_start = strstr(line, TITLE_MARKER))
  477.     {
  478.       strncpy(catalog_header, title_start + strlen(TITLE_MARKER), MAX_HEADER_LEN);
  479.     }
  480. }
  481.  
  482. void catalog_finish_header_function(header)
  483. char *header;
  484. {
  485.   if(strlen(catalog_header) == 0){
  486.     strcpy(header, "Unknown Title");
  487.   }
  488.   else{
  489.     s_strncpy(header, catalog_header, MAX_HEADER_LEN);
  490.   }
  491.   catalog_header[0] = '\0';
  492. }
  493.  
  494.  
  495.  
  496. /* ============================
  497.  * ===  Bio Customizations  ===
  498.  * ============================
  499.  */
  500.  
  501. /* customizations for a DB of genetic abstracts */
  502.  
  503. boolean hit_header = false;
  504.  
  505. boolean bio_separator_function(line)
  506. char *line;
  507. {
  508.   if((strlen(line) > strlen(">>>")) &&
  509.      substrcmp(line, ">>>")){
  510.     return(true);
  511.   }
  512.   else{
  513.     return(false);
  514.   }
  515. }
  516.  
  517. char bio_header[MAX_HEADER_LEN + 1];
  518.  
  519. void bio_header_function(line)
  520. char *line;
  521.  
  522. {
  523.   if(hit_header            /* we just hit a seperator previous to this */
  524.      && (!bio_separator_function(line)) /* we are not on the separator now */
  525.      && strlen(bio_header) == 0){ /* and we have not saved the headline yet */
  526.     strcpy(bio_header, line);
  527.     waislog(WLOG_MEDIUM, WLOG_INDEX, "storing line: %s", bio_header);
  528.     hit_header = false;
  529.   }
  530. }
  531.  
  532. void bio_finish_header_function(header)
  533. char *header;
  534.  
  535. {
  536.   hit_header = true; /* turn on the flag */
  537.   if(strlen(bio_header) == 0){
  538.     strcpy(header, "Unknown Title");
  539.   }
  540.   else{
  541.     strcpy(header, bio_header);
  542.   }
  543.   bio_header[0] = '\0';
  544. }
  545.  
  546. /* =================================
  547.  * ===  CMApp   Customizations  ===
  548.  * =================================
  549.  */
  550.  
  551. boolean cmapp_separator_function(line)
  552. char *line;
  553. {
  554.   if((strlen(line) > strlen("@A")) &&
  555.      substrcmp(line, "@A")){
  556.     /* printf("hit %s\n", line); */
  557.     return(true);
  558.   }
  559.   else{
  560.     return(false);
  561.   }
  562. }
  563.  
  564. char cmapp_header[MAX_HEADER_LEN + 1];
  565.  
  566. void cmapp_header_function(line)
  567. char *line;
  568. {
  569.   if((strlen(line) > strlen("APPLICATION:")) &&
  570.      substrcmp(line, "APPLICATION:")){
  571.     /* printf("hit %s\n", line); */
  572.     s_strncpy(cmapp_header, line + strlen("APPLICATION:"), MAX_HEADER_LEN);
  573.   }
  574. }
  575.  
  576. void cmapp_finish_header_function(header)
  577. char *header;
  578. {
  579.   if(strlen(cmapp_header) == 0){
  580.     s_strncpy(header, "Unknown Title", MAX_HEADER_LEN);
  581.   }
  582.   else{
  583.     s_strncpy(header, cmapp_header, MAX_HEADER_LEN);
  584.   }
  585.   cmapp_header[0] = '\0';
  586. }
  587.  
  588. /* =================================
  589.  * ===  Jargon   Customizations  ===
  590.  * =================================
  591.  *
  592.  * GW - updated for Jargon File 2.9.8
  593.  */
  594.  
  595. /*
  596.  
  597. Format of an entry:
  598.  
  599. [blank line]
  600.  :Title of This entry: first line of text of this entry
  601.    second line of text of this entry
  602.    third line of text of this entry
  603. [blank line]
  604.  
  605. Any line which starts with a colon is considered to be the beginning
  606. of an entry.
  607.  
  608. -GW
  609.  
  610. */
  611.  
  612. static int jargon_seen_entry = 0;
  613.  
  614. boolean jargon_separator_function(line)
  615. register char *line;
  616. {
  617.   if(!jargon_seen_entry && line[0] == ':')
  618.     jargon_seen_entry = 1;
  619.   return line[0] == ':';
  620. }
  621.  
  622. char jargon_header[MAX_HEADER_LEN + 1];
  623.  
  624. void jargon_header_function(line)
  625. char *line;
  626. {
  627.   if(line[0] != ':')
  628.     return;
  629.  
  630.   strncpy(jargon_header,line+1,MAX_HEADER_LEN);
  631.   jargon_header[MAX_HEADER_LEN] = '\0';
  632.  
  633.   if(NULL != (line = strchr(jargon_header,':'))){
  634.     if(line[1] == ':')
  635.       line++;
  636.     line++;
  637.     line[0] = '\0';
  638.   }
  639. }    
  640.  
  641. void jargon_finish_header_function(header)
  642. char *header;
  643. {
  644.   if(jargon_seen_entry) {
  645.     strncpy(header, jargon_header, MAX_HEADER_LEN);
  646.   }
  647.   jargon_header[0] = '\0';
  648. }
  649.  
  650.  
  651. /* =================================
  652.  * ===  Internet Resource Guide  ===
  653.  * =================================
  654.  */
  655.  
  656.  
  657. char irg_header[MAX_HEADER_LEN + 1];
  658. boolean irg_header_set = FALSE;
  659.  
  660. boolean irg_separator_function(line)
  661. char *line;
  662. {
  663.   if(line[0] == 12){  /* control L */
  664.     irg_header_set = FALSE;
  665.     return(true);
  666.   }
  667.   else
  668.     return(false);
  669. }
  670.  
  671. void irg_header_function(line)
  672. char *line;
  673. {
  674.   if((irg_header_set == FALSE) &&
  675.      (line[0] == 32 )){ /* space */
  676.     s_strncpy(irg_header, line + strspn(line, " "), MAX_HEADER_LEN);
  677.     irg_header_set = TRUE;
  678.   }
  679.   
  680. }
  681.  
  682. void irg_finish_header_function(header)
  683. char *header;
  684. {
  685.   if(strlen(irg_header) == 0){
  686.     s_strncpy(header, "Unknown Title", MAX_HEADER_LEN);
  687.   }
  688.   else{
  689.     s_strncpy(header, irg_header, MAX_HEADER_LEN);
  690.   }
  691.   irg_header[0] = '\0';
  692.   irg_header_set = FALSE;
  693. }
  694.  
  695. /* ========================
  696.  * ===  Dash Separator  ===
  697.  * ========================
  698.  */
  699.  
  700.  
  701. /*
  702.  * dash-seperate entries
  703.  * used in Introduction to Algorithms bug.list, suggestions, etc.
  704.  * --------------------... at least 20 dashes
  705.  * header
  706.  * item
  707.  *  ..
  708.  * --------------------... at least 20 dashes
  709.  */
  710.  
  711. boolean dash_separator_function(line)
  712. char *line;
  713. {
  714.   if((strlen(line) > 20) && substrcmp(line,"--------------------")){
  715.     /* printf("hit %s\n", line); */
  716.     return(true);
  717.   }
  718.   else{
  719.     return(false);
  720.   }
  721. }
  722.  
  723. char dash_header[MAX_HEADER_LEN + 1];
  724.  
  725. void dash_header_function(line)
  726. char *line;
  727. {
  728.   if(!dash_separator_function(line) &&
  729.      (strlen(dash_header) < (MAX_HEADER_LEN - 1))){
  730.     s_strncat(dash_header, line, 
  731.           MAX_HEADER_LEN, MAX_HEADER_LEN);
  732.     trim_trailing_newline(dash_header);
  733.     strncat(dash_header, "  ", MAX_HEADER_LEN);
  734.   }
  735. }
  736.  
  737. void dash_finish_header_function(header)
  738. char *header;
  739. {
  740.   if (strlen(dash_header) == 0) {
  741.     strcpy(header, "No Title");
  742.   }
  743.   else {
  744.     s_strncpy(header, dash_header, MAX_HEADER_LEN);
  745.   }
  746.   dash_header[0] = '\0';
  747. }
  748.  
  749.  
  750. /* ============================
  751.  * ===  one_line Separator  ===
  752.  * ============================
  753.  */
  754.  
  755. /* this is where each line is a document (good for databases) */
  756.  
  757. boolean one_line_hit_header = false;
  758.  
  759. boolean one_line_separator_function(line)
  760. char *line;
  761. {
  762.     return(true);
  763. }
  764.  
  765. char one_line_header[MAX_HEADER_LEN + 1];
  766.  
  767. void one_line_header_function(line)
  768. char *line;
  769. {
  770.     s_strncpy(one_line_header, line, MAX_HEADER_LEN);
  771. }
  772.  
  773. void one_line_finish_header_function(header)
  774. char *header;
  775. {
  776.   if (strlen(one_line_header) == 0) {
  777.     strcpy(header, "No Title");
  778.   }
  779.   else {
  780.     s_strncpy(header, one_line_header, MAX_HEADER_LEN);
  781.   }
  782.   one_line_header[0] = '\0';
  783. }
  784.  
  785. /* =============================
  786.  * ===  Paragraph Separator  ===
  787.  * =============================
  788.  */
  789.  
  790. /* paragraph files - seperated by a blank line.  Next line is the header */
  791.  
  792. char para_header[MAX_HEADER_LEN +1];
  793. static boolean para_start = true;
  794.  
  795. boolean para_separator_function(line)
  796. char *line;
  797. {
  798.   if (para_start == true) {
  799.     para_start = false;
  800.     return true;
  801.   }
  802.   if (strlen(line) < 2)
  803.     para_start = true;
  804.   return false;
  805. }
  806.  
  807. void para_header_function(line)
  808. char *line;
  809. {
  810.   if (para_header[0] == 0)
  811.     s_strncpy(para_header, line, MAX_HEADER_LEN);
  812. }
  813.  
  814. void para_finish_header_function(header)
  815. char *header;
  816. {
  817.   if (strlen(para_header) == 0) {
  818.     strcpy(header, "No Title");
  819.   }
  820.   else {
  821.     s_strncpy(header, para_header, MAX_HEADER_LEN);
  822.   }
  823.   para_header[0] = 0;
  824. }  
  825.  
  826. /* ==========================
  827.  * ===  Seeker Separator  ===
  828.  * ==========================
  829.  */
  830.  
  831. boolean seeker_separator_function(line)
  832. char *line;
  833. {
  834.   return(dash_separator_function(line));
  835. }
  836.  
  837. char seeker_header[MAX_HEADER_LEN + 1];
  838. boolean in_headline = FALSE;
  839.  
  840. void seeker_header_function(line)
  841. char *line;
  842. {
  843.   if(strlen(line) > strlen("Headline:") &&
  844.      substrcmp(line, "Headline:")){
  845.     in_headline = TRUE;
  846.     seeker_header[0] = '\0';
  847.     /* printf("hit headline!\n"); */
  848.   }
  849.   else if(in_headline == TRUE &&
  850.       (strlen(seeker_header) < (MAX_HEADER_LEN - 1))){
  851.     s_strncat(seeker_header, line, 
  852.           MAX_HEADER_LEN, MAX_HEADER_LEN);
  853.     trim_trailing_newline(seeker_header);
  854.   }
  855. }
  856.  
  857. void seeker_finish_header_function(header)
  858. char *header;
  859. {
  860.   if (strlen(seeker_header) == 0) {
  861.     strcpy(header, "No Title");
  862.   }
  863.   else {
  864.     s_strncpy(header, seeker_header, MAX_HEADER_LEN);
  865.   }
  866.   seeker_header[0] = '\0';
  867.   in_headline = TRUE;
  868. }  
  869.  
  870. /* ==========================
  871.  * ===  RLIN Separator  ===
  872.  * ==========================
  873.  */
  874.  
  875. boolean rlin_separator_function(line)
  876. char *line;
  877. {
  878.   return(dash_separator_function(line));
  879. }
  880.  
  881. char rlin_header[MAX_HEADER_LEN + 1];
  882. boolean rlin_in_headline = FALSE;
  883.  
  884. void rlin_header_function(line)
  885. char *line;
  886. {
  887.   if(rlin_separator_function(line)){
  888.     rlin_in_headline = TRUE;
  889.     rlin_header[0] = '\0';
  890.     /* printf("hit headline!\n"); */
  891.   }
  892.   else if(rlin_in_headline == TRUE &&
  893.       (strlen(rlin_header) < (MAX_HEADER_LEN - 1))){
  894.     s_strncat(rlin_header, line, 
  895.           MAX_HEADER_LEN, MAX_HEADER_LEN);
  896.     trim_trailing_newline(rlin_header);
  897.   }
  898. }
  899.  
  900. void rlin_finish_header_function(header)
  901. char *header;
  902. {
  903.   if (strlen(rlin_header) == 0) {
  904.     strcpy(header, "No Title");
  905.   }
  906.   else {
  907.     s_strncpy(header, rlin_header, MAX_HEADER_LEN);
  908.   }
  909.   rlin_header[0] = '\0';
  910.   in_headline = TRUE;
  911. }  
  912.  
  913. /* ========================================
  914.  * ===  MH_BBoard  Customizations     ====
  915.  * ========================================
  916.  */
  917.  
  918. /* gcardwel@uci.edu
  919. MH bboards use a series of control A's to do a blank line.. yuk!
  920. */
  921.  
  922. boolean mh_bboard_separator_function(line)
  923. char *line;
  924. {
  925.   static boolean blank_line = false;
  926.  
  927.   if((strlen(line) > strlen("BBoard-ID: ")) &&
  928.      substrcmp(line, "BBoard-ID: ") &&
  929.      blank_line == true){
  930.     blank_line = false;
  931.     return(true);
  932.   }
  933.   
  934.   if(!strcmp(line, "\001\001\001\001\n")){
  935.     blank_line = true;
  936.   }
  937.   else{
  938.     blank_line = false;
  939.   }
  940.   return (false);
  941. }
  942.  
  943. /*
  944.  * Customization for files saved from within the 'rn' newsreader.
  945.  *
  946.  * These can either be in 'mail' format, or they can be in a similar
  947.  * format which starts each article with the pseudo-header
  948.  * 'Article: 42 of comp.sys.foobar'.  Other than that, we treat this
  949.  * just like 'mail'.
  950.  *
  951.  * wollman@uvm.edu, Sun Sep  8 20:12:21 EDT 1991
  952.  */
  953. boolean rn_separator_function(line)
  954. char *line;
  955. {
  956.   if(!strncmp(line,"From ",5) ||
  957.      !strncmp(line,"Article ",7) ||
  958.      !strncmp(line,"Article: ",9))
  959.     return true;
  960.   return false;
  961. }
  962.  
  963. /*
  964.  * Customizations for GNU Emacs Info files
  965.  *
  966.  * When indexing info files, the user must index the files with real text
  967.  * in them, rather than the file with the tag and indirect tables; otherwise
  968.  * you'll end up with lots of garbage in your index.
  969.  *
  970.  * G. Wollman
  971.  */
  972.  
  973. static int done_headline = 0;
  974.  
  975. boolean emacs_info_separator_function(line) /* hate K&R-style definitions */
  976. char *line;
  977. {
  978.   if(line[0] == (char)31) {
  979.     done_headline = 0;
  980.     return true;
  981.   }
  982.   return false;
  983. }
  984.  
  985. static char emacs_info_headline[MAX_HEADER_LEN+1];
  986.  
  987. void emacs_info_header_function(line)
  988. register char *line;
  989. {
  990.   int i;
  991.  
  992.   if(done_headline)
  993.     return;
  994.  
  995.   if(strncmp(line,"File: ",6))
  996.     return;
  997.  
  998.   done_headline = 1;
  999.   line += 6;            /* skip over "File: " */
  1000.  
  1001.   i = 1;
  1002.   emacs_info_headline[0] = '(';
  1003.   while(*line && *line != ',' && (i < MAX_HEADER_LEN-1))
  1004.     emacs_info_headline[i++] = *line++;
  1005.  
  1006.   emacs_info_headline[i++] = ')';
  1007.  
  1008.   line += 9;            /* skip over ", Node: " */
  1009.  
  1010.   /* copy the name of the info node into the headline */
  1011.   while(*line && (i < MAX_HEADER_LEN) && (*line != ','))
  1012.     emacs_info_headline[i++] = *line++;
  1013.  
  1014.   emacs_info_headline[i++] = '\0';
  1015. }
  1016.  
  1017. void emacs_info_finish_header_function(header)
  1018. char *header;
  1019. {
  1020.   strcpy(header,emacs_info_headline);
  1021. }
  1022.  
  1023. /* ========================================
  1024.  * ===    Medline  Customizations      ====
  1025.  * ========================================
  1026.  */
  1027.  
  1028. /* 
  1029.     Francois Schiettecatte
  1030.     with help from:
  1031.     Tom Emmel
  1032.     Karen Phipps
  1033. */
  1034.  
  1035. char medline_header[MAX_HEADER_LEN +1];
  1036. char medline_title[MAX_HEADER_LEN + 1];
  1037. char medline_date[MAX_HEADER_LEN + 1];
  1038. char medline_author[MAX_HEADER_LEN + 1];
  1039.  
  1040. static boolean medline_start = true;
  1041.  
  1042.  
  1043. boolean medline_separator_function(line)
  1044. char *line;
  1045. {
  1046.   if (medline_start == true) {
  1047.     medline_start = false;
  1048.     return true;
  1049.   }
  1050.   if (strlen(line) < 2)
  1051.     medline_start = true;
  1052.   return false;
  1053. }
  1054.  
  1055.  
  1056. void medline_header_function(line)
  1057. char *line;
  1058. {
  1059.  char *ptr;
  1060.  
  1061.  if((strlen(line) > strlen("TI ")) && 
  1062.      (substrcmp(line, "TI "))){    
  1063.     strncpy(medline_title, line + strlen("TI "), MAX_HEADER_LEN);
  1064.   }
  1065.  
  1066.   if((strlen(line) > strlen("SO ")) &&
  1067.      (substrcmp(line, "SO "))){
  1068.    ptr = strchr(line,'1');
  1069.    strncpy(medline_date, ptr, MAX_DATE_LEN);
  1070.   }
  1071.  
  1072.   if((strlen(line) > strlen("AU ")) &&
  1073.      (substrcmp(line, "AU "))){
  1074.     ptr = strtok(line + strlen("AU "),".,");
  1075.     strcpy(medline_author,ptr);
  1076.     strncat(medline_author, "  ", MAX_AUTHOR_LEN); 
  1077.   } 
  1078. }
  1079.  
  1080. void medline_finish_header_function(header)
  1081. char *header;
  1082. {
  1083.   if(strlen(medline_author) > 0 ){
  1084.    strncat(medline_header,medline_author, MAX_HEADER_LEN);
  1085.   }
  1086.   
  1087.   if(strlen(medline_date) > 0 ){
  1088.     strncat(medline_header,"(", MAX_HEADER_LEN);
  1089.     strncat(medline_header,medline_date, MAX_HEADER_LEN);
  1090.     strncat(medline_header,") ", MAX_HEADER_LEN);
  1091.   }
  1092.  
  1093.   if(strlen(medline_title) > 0 ){
  1094.     strncat(medline_header,medline_title, MAX_HEADER_LEN);
  1095.   }
  1096.   
  1097.   if(strlen(medline_header) == 0){
  1098.     strcpy(header, "No Title");
  1099.   }
  1100.   else{
  1101.     strncpy(header, medline_header, MAX_HEADER_LEN);
  1102.   }
  1103.  
  1104.   medline_header[0] = '\0';
  1105.   medline_title[0] = '\0';
  1106.   medline_date[0] = '\0';
  1107.   medline_author[0] = '\0';
  1108. }
  1109.  
  1110.  
  1111.  
  1112.  
  1113. /* ========================================
  1114.  * ===    Refer  Customizations      ====
  1115.  * ========================================
  1116.  */
  1117.  
  1118.  
  1119. /* 
  1120.     Francois Schiettecatte
  1121.     with help from:
  1122.     Tom Emmel
  1123.     Karen Phipps
  1124. */
  1125.  
  1126. char refer_header[MAX_HEADER_LEN +1];
  1127. char refer_title[MAX_HEADER_LEN + 1];
  1128. char refer_date[MAX_HEADER_LEN + 1];
  1129. char refer_author[MAX_HEADER_LEN + 1];
  1130.  
  1131. static boolean refer_start = true;
  1132.  
  1133.  
  1134. boolean refer_separator_function(line)
  1135. char *line;
  1136. {
  1137.   if (refer_start == true) {
  1138.     refer_start = false;
  1139.     return true;
  1140.   }
  1141.   if (strlen(line) < 2)
  1142.     refer_start = true;
  1143.   return false;
  1144. }
  1145.  
  1146.  
  1147. void refer_header_function(line)
  1148. char *line;
  1149. {
  1150.   if((strlen(line) > strlen("%T ")) && 
  1151.      (substrcmp(line, "%T "))){    
  1152.     strncpy(refer_title, line + strlen("%T "), MAX_HEADER_LEN);
  1153.   }
  1154.   else if((strlen(line) > strlen("%B ")) && 
  1155.      (substrcmp(line, "%B ")) && (strlen(refer_title) == 0)){    
  1156.     strncpy(refer_title, line + strlen("%B "), MAX_HEADER_LEN);
  1157.   }
  1158.   
  1159.   if((strlen(line) > strlen("%D ")) &&
  1160.      (substrcmp(line, "%D "))){
  1161.     strncpy(refer_date, line + strlen("%D "), MAX_DATE_LEN);
  1162.   }
  1163.  
  1164.   if((strlen(line) > strlen("%A ")) &&
  1165.      (substrcmp(line, "%A ")) && (strlen(refer_author) == 0)){
  1166.     strncpy(refer_author, line + strlen("%A "), MAX_AUTHOR_LEN);
  1167.     strncat(refer_author, " ", MAX_AUTHOR_LEN);
  1168.   }
  1169.   else if((strlen(line) > strlen("%E ")) &&
  1170.      (substrcmp(line, "%E ")) && (strlen(refer_author) == 0)){
  1171.     strncpy(refer_author, line + strlen("%E "), MAX_AUTHOR_LEN);
  1172.     strncat(refer_author, " ", MAX_AUTHOR_LEN);
  1173.   }
  1174. }
  1175.  
  1176. void refer_finish_header_function(header)
  1177. char *header;
  1178. {
  1179.   if(strlen(refer_author) > 0 ){
  1180.     strncat(refer_header,refer_author, MAX_HEADER_LEN);
  1181.   }
  1182.   
  1183.   if(strlen(refer_date) > 0 ){
  1184.     strncat(refer_header,"(", MAX_HEADER_LEN);
  1185.     strncat(refer_header,refer_date, MAX_HEADER_LEN);
  1186.     strncat(refer_header,") ", MAX_HEADER_LEN);
  1187.   }
  1188.  
  1189.   if(strlen(refer_title) > 0 ){
  1190.     strncat(refer_header,refer_title, MAX_HEADER_LEN);
  1191.   }
  1192.   
  1193.   if(strlen(refer_header) == 0){
  1194.     strncpy(header, "No Title", MAX_HEADER_LEN);
  1195.   }
  1196.   else{
  1197.     strncpy(header, refer_header, MAX_HEADER_LEN);
  1198.   }
  1199.  
  1200.   refer_header[0] = '\0';
  1201.   refer_author[0] = '\0';
  1202.   refer_date[0] = '\0';
  1203.   refer_title[0] = '\0';
  1204. }
  1205.  
  1206.  
  1207.  
  1208.  
  1209. /* ===========================================
  1210.  * ===    First Line  Customizations      ====
  1211.  * ===========================================
  1212.  */
  1213.  
  1214. /* this means the first line of the file is the headline.
  1215.    useful for the lyrics server */
  1216.  
  1217. /* paragraph files - seperated by a blank line.  Next line is the header */
  1218.  
  1219. char first_line_header[MAX_HEADER_LEN +1];
  1220.  
  1221. boolean first_line_separator_function(line)
  1222. char *line;
  1223. {
  1224.   return false;
  1225. }
  1226.  
  1227. void first_line_header_function(line)
  1228. char *line;
  1229. {
  1230.   if (first_line_header[0] == '\0')
  1231.     s_strncpy(first_line_header, line, MAX_HEADER_LEN);
  1232. }
  1233.  
  1234. void first_line_finish_header_function(header)
  1235. char *header;
  1236. {
  1237.   if (strlen(first_line_header) == 0) {
  1238.     strcpy(header, "No Title");
  1239.   }
  1240.   else {
  1241.     s_strncpy(header, first_line_header, MAX_HEADER_LEN);
  1242.   }
  1243.   first_line_header[0] = 0;
  1244. }  
  1245.  
  1246. /* =========================
  1247.  * ===  BIBTEX Separator ===
  1248.  * =========================
  1249.  * S.P.vandeBurgt@research.ptt.nl (Stan)
  1250.  *
  1251.  * BibTeX entries
  1252.  *
  1253.  * @......{
  1254.  * ......
  1255.  * title = header
  1256.  * .......}
  1257.  *
  1258.  */
  1259.  
  1260. static char bibtex_header[MAX_HEADER_LEN + 1];
  1261.  
  1262. boolean bibtex_separator_function(line)
  1263. char *line;
  1264. {
  1265.     char *p = line;
  1266.  
  1267.     while (isspace(*p)) p++; /* skip space */
  1268.     return(*p == '@');
  1269. }
  1270.  
  1271. void bibtex_header_function(line)
  1272. char *line;
  1273. {
  1274.     char *p = line;
  1275.  
  1276.     p = strstr(line, "title");
  1277.     if (p == NULL) p = strstr(line, "Title");
  1278.     if (p == NULL) p = strstr(line, "TITLE");
  1279.     if (p != NULL && (p == line || !isalpha(*(p-1))))
  1280.     {
  1281.       p += 5;
  1282.  
  1283.       while (isspace(*p)) p++; /* skip space */
  1284.       if (*p == '=')          /* should be an '=' now */
  1285.       {
  1286.           p++;
  1287.           /* skip bibtex char's */
  1288.           while (isspace(*p) || *p == '"' || *p == '{') p++;
  1289.           strncpy(bibtex_header, p, MAX_HEADER_LEN);
  1290.           for (p = bibtex_header; *p != '\0'; p++)
  1291.           {
  1292.               /* replace bibtex char's */
  1293.               if (*p == '\n' || *p == '"' || *p == '}' || *p == '{')
  1294.               {
  1295.                   *p = ' ';
  1296.               }
  1297.           }
  1298.       }
  1299.     }
  1300. }
  1301.  
  1302. void bibtex_finish_header_function(header)
  1303. char *header;
  1304. {
  1305.     if (bibtex_header[0] == '\0')
  1306.     {
  1307.       strcpy(header, "Unknown Title");
  1308.     }
  1309.     else{
  1310.       strncpy(header, bibtex_header, MAX_HEADER_LEN);
  1311.     }
  1312.     bibtex_header[0] = '\0';
  1313. }
  1314.  
  1315.  
  1316. /* =========================
  1317.  * ===  NHYP Separator ===
  1318.  * =========================
  1319.  * S.P.vandeBurgt@research.ptt.nl (Stan)
  1320.  * Nhyp entries
  1321.  *
  1322.  * ?:? header
  1323.  * ......
  1324.  * ......
  1325.  *
  1326.  */
  1327.  
  1328. static char nhyp_header[MAX_HEADER_LEN + 1];
  1329.  
  1330. boolean nhyp_separator_function(line)
  1331. char *line;
  1332. {
  1333.     return(strstr(line, "?:?") != NULL);
  1334. }
  1335.  
  1336. void nhyp_header_function(line)
  1337. char *line;
  1338. {
  1339.     char *p = line;
  1340.  
  1341.     p = strstr(line, "?:?");
  1342.     if (p != NULL)
  1343.     {
  1344.       p += 3;
  1345.       while (isspace(*p)) p++; /* skip space */
  1346.       strncpy(nhyp_header, p, MAX_HEADER_LEN);
  1347.       trim_trailing_newline(nhyp_header);
  1348.     }
  1349. }
  1350.  
  1351. void nhyp_finish_header_function(header)
  1352. char *header;
  1353. {
  1354.     if (nhyp_header[0] == '\0')
  1355.     {
  1356.       strcpy(header, "Unknown Title");
  1357.     }
  1358.     else{
  1359.       strncpy(header, nhyp_header, MAX_HEADER_LEN);
  1360.     }
  1361.     nhyp_header[0] = '\0';
  1362. }
  1363.  
  1364.  
  1365.  
  1366. /* ==========================
  1367.  * ===  Objective-C code  ===
  1368.  * ==========================
  1369.  */
  1370.  
  1371.  
  1372. #ifdef NeXT /* only do this if it is on a NeXT */
  1373.  
  1374. /*----------------------- FSA -------------------*/
  1375. #define fsa_max_edges 4
  1376. #define fsa_error_state (-1)
  1377.  
  1378.  
  1379. typedef struct
  1380. {
  1381.     int if_input;
  1382.     int then_goto;
  1383. }
  1384.     fsa_edge;
  1385.  
  1386.  
  1387. /* action (if non-NULL) is excuted before transfer to next state is made */
  1388. /* action takes as arg the int input that will decide the next state */
  1389. typedef struct
  1390. {
  1391.     int default_goto;
  1392.     int n_edges;
  1393.     fsa_edge edges[fsa_max_edges];
  1394.     int (*action)();
  1395. }
  1396.     fsa_vertex;
  1397.  
  1398.  
  1399. int fsa_step(input, state_p, table)
  1400. int input;
  1401. int *state_p;
  1402. fsa_vertex *table;
  1403. {
  1404.     int next_state, e;
  1405.     int (*this_action)();
  1406.  
  1407.  
  1408.     if(*state_p < 0) return(*state_p = fsa_error_state);
  1409.     this_action = table[*state_p].action;
  1410.     if(this_action) this_action(input);
  1411.     for(e=0; e<table[*state_p].n_edges; e++)
  1412.         if(input == table[*state_p].edges[e].if_input)
  1413.         { next_state = table[*state_p].edges[e].then_goto; break; }
  1414.     if(e >= table[*state_p].n_edges) next_state = table[*state_p].default_goto;
  1415.     if(next_state < 0) next_state = fsa_error_state;
  1416.     return(*state_p = next_state);
  1417. }
  1418.  
  1419.  
  1420. /* sends null char as last input, returns final state */
  1421. int fsa_run(s, state_p, table)
  1422. char *s;
  1423. int *state_p;
  1424. fsa_vertex *table;
  1425. {
  1426.     char *p;
  1427.     
  1428.  
  1429.     for(p=s; *p; p++)
  1430.         fsa_step((int) *p, state_p, table);
  1431.     fsa_step(0, state_p, table);
  1432.     return(*state_p);
  1433. }
  1434.  
  1435.  
  1436. /*----------------------- end FSA -------------------*/
  1437.  
  1438.  
  1439. static int wobjc_brace_level = 0;
  1440. static int wobjc_paren_level = 0;
  1441. static int wobjc_strip_state = 0;
  1442. static int wobjc_context = 0;
  1443. static boolean wobjc_separator = false;
  1444. static char wobjc_class[MAX_HEADER_LEN+1];
  1445. static char *wobjc_class_end = 0;
  1446. static char wobjc_header[MAX_HEADER_LEN+1];
  1447. static char *wobjc_header_end = 0;
  1448.  
  1449.  
  1450. #define WOBJC_BLANK " \t\n\r"
  1451. #define WOBJC_WORD "qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM_0123456789"
  1452.  
  1453.  
  1454. /* Flag next line as separator, when context fsa says so. */
  1455. static int wobjc_separate(input)
  1456. int input;
  1457. {
  1458.     return(wobjc_separator = true);
  1459. }
  1460.  
  1461.  
  1462. /* FSA to parse objective-C constructs. */
  1463. static fsa_vertex wobjc_context_fsa[] =
  1464. {
  1465.     { 0, 1, {{ '@', 1 }}},            /* look for objc constructs */
  1466.     { 0, 1, {{ 'i', 20 }}},
  1467.     { 3, 1, {{ ' ', 2 }}},                /* look for @imp class */
  1468.     { 4, 1, {{ 'A', 3 }}},
  1469.     { 4, 3, {{ '+', 6 },{ '-', 8 },{ '@', 10 }}},/* in @imp */
  1470.     { 4, 3, {{ '+', 6 },{ '-', 8 },{ '@', 10 }}, wobjc_separate},
  1471.     { 6, 1, {{ '{', 7 }}},            /* look for -method: */
  1472.     { 5, 1, {{ '{', 7 }}},
  1473.     { 8, 1, {{ '{', 9 }}},            /* look for +method: */
  1474.     { 5, 1, {{ '{', 9 }}},
  1475.     { 4, 1, {{ 'e', 11 }}},            /* look for @end of @imp */
  1476.     { 4, 1, {{ 'n', 12 }}},
  1477.     { 4, 1, {{ 'd', 0 }}},
  1478.     { 14, 1, {{ ' ', 13 }}},               /* look for @intf class */
  1479.     { 15, 1, {{ 'A', 14 }}},
  1480.     { 15, 1, {{ '@', 16 }}},            /* in @intf */
  1481.     { 15, 1, {{ 'e', 17 }}},            /* look for @end of @intf */
  1482.     { 15, 1, {{ 'n', 18 }}},
  1483.     { 15, 1, {{ 'd', 19 }}},
  1484.     { 0, 1, {{ '@', 1 }}, wobjc_separate},
  1485.     { 0, 2, {{ 'm', 21 },{ 'n', 33 }}},        /* look for @impl */
  1486.     { 0, 1, {{ 'p', 22 }}},
  1487.     { 0, 1, {{ 'l', 23 }}},
  1488.     { 0, 1, {{ 'e', 24 }}},
  1489.     { 0, 1, {{ 'm', 25 }}},
  1490.     { 0, 1, {{ 'e', 26 }}},
  1491.     { 0, 1, {{ 'n', 27 }}},
  1492.     { 0, 1, {{ 't', 28 }}},
  1493.     { 0, 1, {{ 'a', 29 }}},
  1494.     { 0, 1, {{ 't', 30 }}},
  1495.     { 0, 1, {{ 'i', 31 }}},
  1496.     { 0, 1, {{ 'o', 32 }}},
  1497.     { 0, 1, {{ 'n', 2 }}},
  1498.     { 0, 1, {{ 't', 34 }}},            /* look for @intf */
  1499.     { 0, 1, {{ 'e', 35 }}},
  1500.     { 0, 1, {{ 'r', 36 }}},
  1501.     { 0, 1, {{ 'f', 37 }}},
  1502.     { 0, 1, {{ 'a', 38 }}},
  1503.     { 0, 1, {{ 'c', 39 }}},
  1504.     { 0, 1, {{ 'e', 13 }}}
  1505. };
  1506.  
  1507.  
  1508. /* Action to be used by stripping fsa in non-commented, non-quoted state. */
  1509. /* This runs context fsa. */
  1510. static int wobjc_process_stripped_code(input)
  1511. int input;
  1512. {
  1513.     int context_input;
  1514.     
  1515.  
  1516.     switch(input)
  1517.     {
  1518.         /* Increment brace/paren levels as appropriate. */
  1519.     case '{': wobjc_brace_level++; break;
  1520.     case '}': if(wobjc_brace_level > 0) wobjc_brace_level--; break;
  1521.     case '(': wobjc_paren_level++; break;
  1522.     case ')': if(wobjc_paren_level > 0) wobjc_paren_level--; break;
  1523.     case '\"': break;
  1524.     case '\'': break;
  1525.     case '/': break;
  1526.         
  1527.     default:
  1528.     /* If in correct context and not in brace/paren/comment/quote, */
  1529.     /* then record header info.  */
  1530.         if(wobjc_brace_level==0 && wobjc_paren_level==0)
  1531.     {
  1532.         /* Recording class or instance method.  Ignore multiple blanks. */
  1533.         if(wobjc_context==6 || wobjc_context==8)
  1534.         {
  1535.         if(!wobjc_header_end || wobjc_header_end==wobjc_header)
  1536.         {
  1537.             strcpy(wobjc_header, (wobjc_context==6 ? "+[" : "-["));
  1538.             strcat(wobjc_header, wobjc_class);
  1539.             strcat(wobjc_header, " ");
  1540.             wobjc_header_end = wobjc_header+strlen(wobjc_header);
  1541.         }
  1542.         if((wobjc_header_end - wobjc_header)<(MAX_HEADER_LEN-5)
  1543.             && !(strchr(WOBJC_BLANK, *(wobjc_header_end-1))
  1544.             && strchr(WOBJC_BLANK, input)))
  1545.             { *wobjc_header_end+= input; *wobjc_header_end = 0; }
  1546.         }
  1547.         
  1548.  
  1549.         /* Recording class name for @implementation or @interface. */
  1550.         if(strchr(WOBJC_WORD, input)
  1551.             && (wobjc_context==2 || wobjc_context==3
  1552.             || wobjc_context==13 || wobjc_context==14))
  1553.         {
  1554.             if(wobjc_context==2 || wobjc_context==13 || !wobjc_class_end)
  1555.             wobjc_class_end = wobjc_class;
  1556.             if(wobjc_context==13
  1557.             || (wobjc_context==14 && !wobjc_header_end))
  1558.             wobjc_header_end = wobjc_header;
  1559.         if((wobjc_class_end - wobjc_class_end)<(MAX_HEADER_LEN/2))
  1560.             { *wobjc_class_end+= input; *wobjc_class_end = 0; }
  1561.         if((wobjc_context==13 || wobjc_context==14)
  1562.             && (wobjc_header_end-wobjc_header_end)<(MAX_HEADER_LEN/2))
  1563.             { *wobjc_header_end+= input; *wobjc_header_end = 0; }
  1564.         }
  1565.     }
  1566.     
  1567.     /* Since not in comment/quote, run context fsa. */
  1568.     /* Input is modified like this: */
  1569.     /*    Non-zero brace level => '{'. */
  1570.     /*    Else spaces => ' '. */
  1571.     /*    Else if in correct contexts, word letters => 'A'. */
  1572.     context_input = input;
  1573.     if(wobjc_brace_level>0) context_input = '{';
  1574.     else if(strchr(WOBJC_BLANK, input)) context_input = ' ';
  1575.     else if((wobjc_context==3 || wobjc_context==14)
  1576.         && strchr(WOBJC_WORD, input))
  1577.             context_input = 'A';
  1578.     fsa_step(context_input, &wobjc_context, wobjc_context_fsa);
  1579.     break;
  1580.     }
  1581.     return(true);
  1582. }
  1583.  
  1584.  
  1585. /* FSA to strip out comments and quotes. */
  1586. static fsa_vertex wobjc_strip_fsa[] =
  1587. {
  1588.     { 0, 3, {{ '/', 1 },{ '\"', 5 },{ '\'', 7 }}, wobjc_process_stripped_code},
  1589.     { 0, 2, {{ '*', 2 },{ '/', 4 }}},        /* look for comment */
  1590.     { 2, 1, {{ '*', 3 }}},            /* in /* comment */
  1591.     { 2, 2, {{ '/', 0 },{ '*', 3 }}},
  1592.     { 4, 1, {{ '\n', 0 }, { '\0', 0 }}},    /* in // comment */
  1593.     { 5, 2, {{ '\\', 6 },{ '\"', 0 }}},        /* in " quote */
  1594.     { 5, 0, },
  1595.     { 7, 2, {{ '\\', 8 },{ '\'', 0 }}},        /* in ' quote */
  1596.     { 7, 0, }
  1597. };
  1598.  
  1599.  
  1600. boolean wobjc_separator_function(line)
  1601. char *line;
  1602. {
  1603.     if(wobjc_separator) { wobjc_separator = false; return true; }
  1604.     else return false;
  1605. }
  1606.  
  1607.  
  1608. void wobjc_header_function(line)
  1609. char *line;
  1610. {
  1611.     /* Run stripping fsa, which will run context fsa. */
  1612.     fsa_run(line, &wobjc_strip_state, wobjc_strip_fsa);
  1613.     return;
  1614. }
  1615.  
  1616.  
  1617. void wobjc_finish_header_function(header)
  1618. char *header;
  1619. {
  1620.     char *p;
  1621.     
  1622.  
  1623.     /* Flush terminal blanks and balance opening '[' if any. */
  1624.     for(p=wobjc_header+strlen(wobjc_header);
  1625.         p>wobjc_header && strchr(WOBJC_BLANK, *(p-1)); p--);
  1626.     if(wobjc_header[0]=='+' || wobjc_header[0]=='-') *p+= ']';
  1627.     *p = 0;
  1628.     
  1629.  
  1630.     /* Copy out final header. */
  1631.     strcpy(header, wobjc_header);
  1632.     wobjc_header[0] = 0;
  1633.     wobjc_header_end = wobjc_header;
  1634.     return;
  1635. }
  1636.  
  1637. #endif /* def NeXT */
  1638.  
  1639.  
  1640. /* ==============================
  1641.  * ===  Ziff computer select  ===
  1642.  * ==============================
  1643.  */
  1644.  
  1645. /* these filters index ziff computer select cd-rom files that
  1646.    have been offloaded from the CDROM.  This is for indexing
  1647.    the CACM files that have been explicitly ok'ed by ACM.
  1648.    All other uses would violate the no lan access restrictions
  1649.    of Ziff */
  1650.  
  1651.  
  1652. #define ZIFF_TITLE_MARKER_1 "Title:     "
  1653. #define ZIFF_TITLE_MARKER_2 "Company:   "
  1654. #define ZIFF_FIRST_LINE_MARKER " *****"
  1655.  
  1656. /* just use the title */
  1657.  
  1658. boolean ziff_separator_function(line)
  1659. char *line;
  1660. {
  1661.   if (strstr(line, ZIFF_FIRST_LINE_MARKER)) {
  1662.     return(true);
  1663.   }
  1664.   else{
  1665.     return(false);
  1666.   }
  1667. }
  1668.  
  1669. char ziff_header[MAX_HEADER_LEN + 1];
  1670.  
  1671. void ziff_header_function(line)
  1672. char *line;
  1673. {
  1674.   if (strstr(line, ZIFF_TITLE_MARKER_1) ||
  1675.       strstr(line, ZIFF_TITLE_MARKER_2))
  1676.     {
  1677.       strncpy(ziff_header, line + strlen(ZIFF_TITLE_MARKER_1), 
  1678.           MAX_HEADER_LEN);
  1679.     }
  1680. }
  1681.  
  1682. void ziff_finish_header_function(header)
  1683. char *header;
  1684. {
  1685.   if(strlen(ziff_header) == 0){
  1686.     strcpy(header, "Unknown Title");
  1687.   }
  1688.   else{
  1689.     s_strncpy(header, ziff_header, MAX_HEADER_LEN);
  1690.   }
  1691.   ziff_header[0] = '\0';
  1692. }
  1693.  
  1694. /* special header function for filename only type */
  1695.  
  1696. void filename_finish_header_function(header)
  1697. char* header;
  1698. {
  1699.   char *p = strrchr(current_filename, '/');
  1700.  
  1701.   if (p != NULL) {
  1702.     p++;
  1703.   } else {
  1704.     p = current_filename;
  1705.   }
  1706.  
  1707.   s_strncpy(header, p, MAX_HEADER_LEN);
  1708. }
  1709.  
  1710.  
  1711.  
  1712.  
  1713. /* ==============================
  1714.  * ===  SCO ERG mail threads Customizations  ===
  1715.  * hess
  1716.  * ==============================
  1717.  */
  1718.  
  1719. /* separator_function is called on every line to see if it
  1720.  * separates documents.
  1721.  */
  1722. static int erg_thread_line_no = 0; 
  1723. static int lines_to_use = 0; 
  1724. static int saw_act_queue = 0; 
  1725. static int size_of_act_queue = 0; 
  1726.  
  1727. #define INIT    register char *sp = instring;
  1728. #define GETC()  (*sp++)
  1729. #define PEEKC() (*sp)
  1730. #define UNGETC(c)        (--sp)
  1731. #define RETURN(c)        return;
  1732. #define ERROR(c)         regerr()
  1733. #include <regexp.h>
  1734.  
  1735. regerr() { printf("oops, regerr()\n"); }
  1736.  
  1737. #define ESIZE 256
  1738. static char expbuf[ESIZE] = { "" } ;  
  1739. static char Customer[MAX_HEADER_LEN + 1] = { "" }; 
  1740. static char Support_Reps[MAX_HEADER_LEN + 1]=  { "" }; 
  1741. static char descript[MAX_HEADER_LEN + 1]=  { "" }; 
  1742. static char erg_id[MAX_HEADER_LEN + 1]=  { "" }; 
  1743. static int once = 0; 
  1744. static int saw_descript = 0;
  1745.  
  1746. boolean erg_thread_separator_function(line)
  1747. char *line;
  1748. {
  1749.   if ( !once  ) {  
  1750.     once++; 
  1751.     compile( "PROBLEM", expbuf, &expbuf[ESIZE], '\0');
  1752.     }
  1753.  
  1754.   if(lines_to_use==0) {      /* get from environment, default 300 */
  1755.     char *env = getenv("LINES_TO_INDEX");  
  1756.     lines_to_use = ( env ? atoi(env) : 300 ); 
  1757.   }
  1758.   erg_thread_line_no++; 
  1759.  
  1760. /* the threads (at least from support ) 
  1761.  * have a section that we want to skip, it starts with : 
  1762. Active OS queue
  1763. ==========================
  1764. 1. .....
  1765.  
  1766. * This contains every open item on the queue, so a query on customer 
  1767. * name will turn up in many threads that are unrelated.
  1768. * I just skip till a "From" line from the occurance of 
  1769. "Active OS queue"
  1770. */
  1771. if ( substrcmp(line, "Active OS queue") )  { 
  1772.     saw_act_queue = 1; 
  1773. if ( saw_act_queue && substrcmp(line,"From") ) {
  1774.     saw_act_queue = 0;
  1775. }
  1776. if ( saw_act_queue ) { 
  1777.     line[0] = '\0'; /* null the line, so it won't be indexed */
  1778. }
  1779.  
  1780.   /* since one thread is one object, we never see a seperator. 
  1781.    * just check our total indexed size 
  1782.    */
  1783.   if (erg_thread_line_no >= lines_to_use )  { 
  1784.     /* seek ahead to end of file, allows us to skip indexing 
  1785.      * bulk of very large files.
  1786.      * fp = input_stream, size = file_size
  1787.      */
  1788.     extern FILE *input_stream;
  1789.     fseek(input_stream , 0L, SEEK_END);
  1790.   } 
  1791.   return(false);
  1792. }
  1793.  
  1794. /*   
  1795. * header_function is called on every line so that a headline
  1796. *  can be accumulated.  This assumes that it will side effect global
  1797. *  variables.
  1798. */
  1799. void erg_thread_header_function(line)
  1800. char *line;
  1801. {
  1802.   if( (strlen(line) > strlen("Subject: ")) 
  1803.       && substrcmp(line, "Subject: ") ) 
  1804.   { 
  1805.     if (strlen(mail_subject) == 0) {
  1806.         strcpy(mail_subject, "Re: ");
  1807.         s_strncat(mail_subject, line + strlen("Subject: "), MAX_HEADER_LEN, MAX_HEADER_LEN);
  1808.         trim_trailing_newline(mail_subject);
  1809.     }
  1810.  
  1811.     /* since this is a subject, look for the erg#### so we can put it in the header */ 
  1812.     if (strlen(erg_id) == 0 ) 
  1813.     { 
  1814.     char *p = line; 
  1815.           while ( p[0] && p[1] && p[2] && p[3] && p[4] && p[5] && p[6] ) 
  1816.         {     
  1817.         if (p[0] == 'e' && p[1] == 'r' &&  p[2] == 'g' 
  1818.         && (p[3] >= '0' && p[3] <= '9')
  1819.         && (p[4] >= '0' && p[4] <= '9')
  1820.         && (p[5] >= '0' && p[5] <= '9')
  1821.         && (p[6] >= '0' && p[6] <= '9') ) 
  1822.         { 
  1823.             strcpy(erg_id,p); 
  1824.             *p = erg_id[7] = '\0';
  1825.         } 
  1826.     p++; 
  1827.         } 
  1828.      }
  1829.   }
  1830.   else if((strlen(line) > strlen("From: ")) &&
  1831.      substrcmp(line, "From: ") &&
  1832.      (strlen(mail_from) == 0)){
  1833.     /* this should find the <foo@bar> field in the from list */
  1834.     s_strncpy(mail_from, line + strlen("From: "), MAX_HEADER_LEN);
  1835.     trim_trailing_newline(mail_from);
  1836.   }
  1837.  
  1838.   /* grab the customer name if we see it ! */
  1839.   if ( strlen(Customer) == 0 && (substrcmp(line, "Customer") || 
  1840.         substrcmp(line, "Company") ) && 
  1841.              (strlen(line) > strlen("Customer"))  ) 
  1842.   { 
  1843.     char *p = strchr(line,':'); 
  1844.     if (*p == ':') *p++; 
  1845.     while( *p && (*p == ' ' || *p == '\t') ) *p++; 
  1846.     s_strncpy(Customer, p, MAX_HEADER_LEN); 
  1847. #define CUST_MAX 15
  1848.         if(strlen(Customer) > CUST_MAX) Customer[CUST_MAX] = '\0';
  1849.     trim_trailing_newline(Customer);
  1850.   }
  1851. #if 0 /* not working yet, descripts are sort of different among threads */
  1852.   if ( ! descript[0] && ! saw_descript && step(line, expbuf) ) 
  1853.   {  /* the next non blank line is our descript ?*/
  1854.     saw_descript = 1;
  1855.   } else {   
  1856.    /* if (saw_descript) printf("line <%s> \n",line); */
  1857.    if (saw_descript && strlen(line) > 4) { 
  1858.     strcpy(descript, line); 
  1859.     /*     printf("descript <%s> \n",descript);  */
  1860.     saw_descript = 0; 
  1861.    }
  1862.  } 
  1863. #endif
  1864. }
  1865.  
  1866.  
  1867. /* 
  1868. * finish_header_function is called when the document is finished
  1869. *  (by separator function responding TRUE or EOF) this will return
  1870. *  the headline string or NULL.
  1871. *  Presumably finish_header_function will use the
  1872. *  effects of header_function.  finish_header_function
  1873. *  will only be called once, so it should clear whatever state
  1874. *  header_function has set.
  1875. */
  1876. void erg_thread_finish_header_function(header)
  1877. char *header;
  1878. {
  1879. header[0] = '\0';
  1880.   if(strlen(mail_subject) != 0 &&
  1881.      strlen(mail_from) != 0){
  1882.     /* trim the from line if needed */
  1883.     if(strlen(mail_from) > 10){
  1884.       mail_from[10] = '\0';
  1885.     }
  1886.     s_strncpy(header, mail_from, MAX_HEADER_LEN);
  1887.     s_strncat(header, " ", MAX_HEADER_LEN, MAX_HEADER_LEN);
  1888.     s_strncat(header, mail_subject, MAX_HEADER_LEN, MAX_HEADER_LEN);
  1889.   }
  1890.   else if(strlen(mail_subject) != 0){
  1891.     s_strncpy(header, mail_subject, MAX_HEADER_LEN);
  1892.   }
  1893.   else if(strlen(mail_from) != 0){
  1894.     s_strncpy(header, mail_from, MAX_HEADER_LEN);
  1895.   }
  1896.   else{
  1897.     strcpy(header, "Unknown Subject");
  1898.   }
  1899.   if( strlen(Customer) > 0 )  { 
  1900.     strcat(Customer, " "); 
  1901.     strcat(Customer, header); 
  1902.     strcpy(header, Customer); 
  1903.   }
  1904.   if ( strlen(erg_id) > 0 ) { 
  1905.     strcat(header, " ");     
  1906.     strcat(header, erg_id);     
  1907.   }
  1908. /* 
  1909.   if( strlen(descript) > 0 ) 
  1910.     strcat(header, descript); 
  1911. */
  1912. printf("    <%s>\n",header);
  1913.  
  1914. /* clean up */
  1915.   mail_from[0] = '\0';
  1916.   mail_subject[0] = '\0';
  1917.   descript[0] = '\0';
  1918.   Customer[0] = '\0';
  1919.   erg_id[0] = '\0';
  1920. erg_thread_line_no = 0;
  1921. saw_act_queue = 0; 
  1922. saw_descript = 0;
  1923.  
  1924. }
  1925.  
  1926.  
  1927.